<?php
/**   
  *
  * Copyright (c) 2009, Persistent Systems Limited
  *
  * Redistribution and use, with or without modification, are permitted 
  *  provided that the following  conditions are met:
  *   - Redistributions of source code must retain the above copyright notice, 
  *     this list of conditions and the following disclaimer.
  *   - Neither the name of Persistent Systems Limited nor the names of its contributors 
  *     may be used to endorse or promote products derived from this software 
  *     without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
  
/**
  *
  * This file contains the definition of QueryProcessor class.
  */
  
/**
  * The QueryProcessor Class.
  */
class QueryProcessor {
    protected $_query;
    protected $_encodedquery;
    protected $_entityname;
    protected $_entityname1;
    protected $_params = array();
    protected $_queryOptions = Array('$expand', '$filter', '$orderby', '$skip', '$top');
    public $_entitiesInPath = array();

    /**
     * Constructs a new QueryProcessor object.
     * @param string $csQuery The query to be executed.
     */
    public function __construct($csQuery) 
    {
        $this->_query = $csQuery;
        $index = strpos($this->_query, "?");
        if ($index != FALSE) 
        {
            $this->SplitQuery($index);
            $paramstr = substr($this->_query, $index+1);
            $this->BuildParamArray($paramstr);
            $this->buildEncodedURL();
        } 
        else 
        {
            $index = strlen($this->_query);
            $this->SplitQuery($index);
            $this->_encodedquery = str_replace(' ', "%20", $csQuery);
        }
    }

    /**
     * Function to populate _entityname and _entitiesInPath[].
     * @param int $index index from where the query options atart.
     */
    protected function SplitQuery($index)
    {
        $tmp = substr($this->_query, 0, $index);
        $len = strlen($this->_query);
        $this->_entityname1 = $tmp;
        $lastSlash = Utility::reverseFind($tmp, '/');
        $lastSlash++;
        $this->_entityname  = substr($this->_query, $lastSlash, ($index - $lastSlash));
        {
            $index1 = strpos($this->_entityname, "(");
            if ($index1 != FALSE)
            {
                $this->_entityname = substr($this->_entityname, 0, $index1);
            }
        }
        $entitiesInPath   = split ( "/" , $tmp);
        foreach ($entitiesInPath as $entity) 
        {
            $index1 = strpos($entity, "(");
            if ($index1 != FALSE)
            {
                $entity = substr($entity, 0, $index1);
            }
            
            $this->_entitiesInPath[] = $entity;
        }
    }

    /**
     * Function to populate the array _params which will hold the query
     * options.
     * @param string $paramstr The query options as a string
     */
    protected function buildParamArray($paramstr)
    {
        $params   = split ( "&" , $paramstr);
        foreach ($params as $param) 
        {
            $index = strpos($param, "=");
            if ($index != FALSE) 
            {
                $Name  = substr($param, 0, $index);
                $Name  = trim($Name);
                $Value = substr($param, $index+1);
                $this->_params[$Name]= $Value;
            }
        }
    }

     /**
     * Function to populate the _encodedquery which will
     * hold the encoded query.
     */
    protected function buildEncodedURL()
    {
        $this->_encodedquery = $this->_entityname1;
        $this->_encodedquery = $this->_encodedquery."?";
        $count = Count($this->_params);
        $i = 0;
        foreach ($this->_params as $k => $v) 
        {
            $this->_encodedquery = $this->_encodedquery.$k;
            $this->_encodedquery = $this->_encodedquery."=";
            $this->_encodedquery = $this->_encodedquery.urlencode($v);
            $i++;
            if ($i != $count) 
            {
                $this->_encodedquery = $this->_encodedquery."&";
            }
        }
    }

     /**
     * Function to get actual entity name. This function
     * is required because the query string can also contain
     * navigation property name, its possible that navigation
     * name will be different from the actual entity type of
     * navigation.
     */
    public function getEntityNameFromQP()
    {
        if (count($this->_entitiesInPath) >= 2) 
        {
            $i = 0;
            $entityName = $this->_entitiesInPath[$i];
            for (;$i < count($this->_entitiesInPath)-1; $i++) 
            {
                $entityObj = Utility::getEntity($entityName ,"");
                $entityName = $entityObj->getActualEntityTypeName($this->_entitiesInPath[$i+1]);
            }
        } 
        else 
        {
            $entityName = $this->get_entityname();
        }
        return $entityName;
    }

    /**
     * Function to get the encoded query
     */
    public function get_encodedquery()
    {
        return $this->_encodedquery;
    }

    /**
     * Function to get the entity name
     */
    function get_entityname()
    {
        return $this->_entityname;
    }
}
?>